package com.cmcc.volte.xdr;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cmcc.sdtp.client.Messagedispose;

import com.cmcc.volte.xdr.SigXDR.SigXDR;
import com.cmcc.volte.xdr.util.MessageUtil;
import com.google.common.hash.HashCode;

//import com.cmcc.volte.xdr.client.Messagedispose;
//import com.cmcc.volte.xdr.client.client;

public class GetXdr {

	private static Logger logger = LogManager.getLogger(GetXdr.class);
	private static String directory;
	public static ByteBuffer buffer;

	private static byte[] gHeader = { (byte) 0xd4, (byte) 0xc3, (byte) 0xb2, (byte) 0xa1, 
		(byte) 0x02, (byte) 0x00, (byte) 0x04, (byte) 0x00, 
		(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
		(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
		(byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, 
		(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00 };

	public static SigXDR getSigXDR(int interFace, String xdrId, long startTime,String defaultName) {
//		xdrId = "00000000000000005837d8c3cc14943f";
		ByteBuffer byteArray = ByteBuffer.allocate(2);
		File datFile = null;
		int statusType = 100;
		directory = GetXdr.class.getResource("/files/pcap/").getFile();
		logger.info("localhost:file= " + directory + xdrId + ".dat");
		datFile = new File(directory + xdrId + ".dat");
		FileChannel in = null;
		FileInputStream fis = null;
		// 查找本地存储文件
		if (datFile.exists()) {
			logger.info("本地存在，查找本地"+xdrId);
			try {
				fis = new FileInputStream(datFile);
				in = fis.getChannel();
				ByteBuffer buffer = ByteBuffer.allocate(2);
				in.read(buffer);
				in.read(ByteBuffer.allocate(7));
				int totalLength = MessageUtil.toBigInteger(buffer.array()).intValue();
				byteArray = ByteBuffer.allocate(totalLength - 9);
				in.read(byteArray);
//				sp(directory + xdrId, new SigXDR(byteArray,"1"));
			} catch (IOException e) {
				logger.error("原始信令码流,本地查询异常：",e);
				e.printStackTrace();
			} finally {
				try {
					in.close();
				} catch (IOException e) {
					logger.error("原始信令码流,本地异常：",e);
				}
				try {
					fis.close();
				} catch (IOException e) {
					logger.error("原始信令码流，本地关闭流异常：",e);
				}
			}
		} else {
			logger.info("原始信令码流本地没找到，调用反查接口。"+xdrId);
			// 请求客户端
			FileOutputStream fop = null;
			try {
//				client clent = new client();
//				clent.initSocket();
				Messagedispose m = new Messagedispose();
				byteArray = m.controller(interFace, xdrId, startTime);
				buffer = byteArray;//这个引用传递，不是复制对象
				buffer.flip();  //
				int length = MessageUtil.toBigInteger(loadByte(2)).intValue();
				int messageType = MessageUtil.toBigInteger(loadByte(2)).intValue();
				int sequenceId = MessageUtil.toBigInteger(loadByte(4)).intValue();
				int totalContents = MessageUtil.toBigInteger(loadByte(1)).intValue();
				int result = MessageUtil.toBigInteger(loadByte(1)).intValue();
				logger.info("头信息：totallength---"+length+",messageType---"+messageType+",sequenceId---"+sequenceId+",totalContents---"+totalContents+",result---"+result);
				if(result == 1){
					// 保存为dat文件
					logger.info("保存为dat文件==="+xdrId);
					datFile.createNewFile();
					fop = new FileOutputStream(datFile);
					fop.write(byteArray.array());
					// 保存为pcap文件
					SigXDR sigXDR = new SigXDR(byteArray,"2");
					sp(directory + xdrId, sigXDR);
					return sigXDR;
				}else{
					statusType = 101;
					xdrId = defaultName;//如果反查接口出现故障，则查询本地的默认pcap
					logger.error("接口请求返回失败，获取当前默认的pcap文件，xdrId=="+xdrId);
					try {
						datFile = new File(directory + xdrId + ".dat");
						// 查找本地存储文件
						if (datFile.exists()) {
							fis = new FileInputStream(datFile);
							in = fis.getChannel();
							ByteBuffer buffer = ByteBuffer.allocate(2);
							in.read(buffer);
							in.read(ByteBuffer.allocate(7));
							int totalLength = MessageUtil.toBigInteger(buffer.array()).intValue();
							byteArray = ByteBuffer.allocate(totalLength - 9);
							in.read(byteArray);
						}
					} catch (Exception e1) {
						logger.error("默认原始信令码流,本地查询异常：",e1);
						e1.printStackTrace();
					}
				}
			} catch (Exception e) {
				statusType = 101;
				logger.error(xdrId + "原始信令码流接口反查异常：",e);
				xdrId = defaultName;//如果反查接口出现故障，则查询本地的默认pcap

				logger.error("原始信令码流接口反查异常，获取当前默认的pcap文件，xdrId=="+xdrId);
				try {
					datFile = new File(directory + xdrId + ".dat");
					// 查找本地存储文件
					if (datFile.exists()) {
						fis = new FileInputStream(datFile);
						in = fis.getChannel();
						ByteBuffer buffer = ByteBuffer.allocate(2);
						in.read(buffer);
						in.read(ByteBuffer.allocate(7));
						int totalLength = MessageUtil.toBigInteger(buffer.array()).intValue();
						byteArray = ByteBuffer.allocate(totalLength - 9);
						in.read(byteArray);
					}
				} catch (Exception e1) {
					logger.error("默认原始信令码流,本地查询异常：",e1);
					e.printStackTrace();
				}
			}finally{
				if(fop != null){
					try {
						fop.flush();
					} catch (IOException e) {
						logger.error("原始信令码流,流flush关闭异常：",e);
					}
					try {
						fop.close();
					} catch (IOException e) {
						logger.error("原始信令码流,流close关闭异常：",e);
					}
					
				}
			}
		}
		SigXDR sxdr = new SigXDR(byteArray,"1");
		sxdr.setStatusType(statusType);
		return sxdr;
	}
	
	
	
	public static void main(String[] args) {
//		System.out.println(getString(getByteBuffer("abcdef")));
		ByteBuffer sss = getByteBuffer("A000006778");
		buffer = sss;
		int length = MessageUtil.toBigInteger(loadByte(1)).intValue();
		System.out.println("11===="+length);
		int length2 = MessageUtil.toBigInteger(loadByte(1)).intValue();
		System.out.println("22===="+length2);
		int length3 = MessageUtil.toBigInteger(loadByte(1)).intValue();
		System.out.println("3===="+length3);
	}
	
	public static ByteBuffer getByteBuffer(String str)
    {
        return ByteBuffer.wrap(str.getBytes());
    }
	 
	/**
     * ByteBuffer 转换 String
     * @param buffer
     * @return
     */
    public static String getString(ByteBuffer buffer)
    {
        Charset charset = null;
        CharsetDecoder decoder = null;
        CharBuffer charBuffer = null;
        try
        {
            charset = Charset.forName("UTF-8");
            logger.info("----1----"+charset);
            decoder = charset.newDecoder();
            logger.info("----2----"+decoder);
//             charBuffer = decoder.decode(buffer);//用这个的话，只能输出来一次结果，第二次显示为空
//             logger.info("----34----"+charBuffer.toString());
            charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
            logger.info("----3----"+charBuffer.toString());
            return charBuffer.toString();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            logger.error(ex);
            return "0909090";
        }
    }

	private static void sp(String directory, SigXDR sigXDR) {
		logger.info("保存为pcap文件==="+directory);
		File file = new File(directory + ".pcap");
		FileOutputStream fop = null;
		try {
			file.createNewFile();
			fop = new FileOutputStream(file);
			logger.info(fop+"开始创建文件===" + file.getName()+"---"+gHeader);
			fop.write(gHeader);
			for (int i = 0; i < sigXDR.getHeader().getSize(); i++) {
				byte[] load = sigXDR.getData().get(i).getLoad();
				long times = sigXDR.getData().get(i).getTime_s();
//				long timens = sigXDR.getData().get(i).getTime_ns()/1000;
				//逻辑由原来的直接截取后三位改为四舍五入
				long timens = sigXDR.getData().get(i).getTime_ns();
				double tempTime =new Double(Math.round((double)timens)/1000.0);
				timens = Math.round((int)Math.rint(tempTime));
//				System.out.println(times+"==="+timens);
				// 时间
				fop.write(change(toByteArray(times, 4)));
				fop.write(change(toByteArray(timens, 4)));
				// 长度
				fop.write(change(toByteArray(load.length, 4)));
				fop.write(change(toByteArray(load.length, 4)));
				fop.write(load);
			}
		} catch (Exception e) {
			logger.error("sp生成pcap文件异常：",e);
			e.printStackTrace();
		}finally{
			if(fop != null){
				try {
					fop.flush();
				} catch (IOException e) {
					logger.error("sp生成pcap文件异常：",e);
					e.printStackTrace();
				}
				try {
					fop.close();
				} catch (IOException e) {
					logger.error("sp生成pcap文件异常：",e);
					e.printStackTrace();
				}
			}
		}
		logger.info("存储完成==="+directory);
	}

	/**
	 * 从buff中读取指定长度的数据,buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public static byte[] loadByte(int length) {
		byte[] temp = new byte[length];
		buffer.get(temp);
		return temp;
	}

	/**
	 * @comment 从buff中读取指定长度的数据被将其转换为ip地址。ipv4仅占用四个字节所以将多余的截去。
	 * 
	 * @param length
	 * @return
	 */
	public String loadIp(int length) {
		return MessageUtil.toIpAddress(loadByte(length));
	}

	/**
	 * 从buff中读取指定长度的数据并转换为long buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public long loadLong(int length) {
		return MessageUtil.toBigInteger(loadByte(length)).longValue();

	}

	/**
	 * 从buff中读取指定长度的数据并转换为int buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public int loadInt(int length) {
		return MessageUtil.toBigInteger(loadByte(length)).intValue();
	}

	/**
	 * 从buff中读取指定长度的数据并转换为string buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public String loadStr(int length) {
		return new String(loadByte(length));
	}

	/**
	 * 从buff中读取指定长度的数据并转换为16进制Hash str, buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public String loadHexStr(int length) {
		return HashCode.fromBytes(loadByte(length)).toString();
	}

	/**
	 * 从buff中读取指定长度的数据,buffer的pos会改变所以需要按顺序读取
	 * 
	 * @param length
	 * @return
	 */
	public byte[] load(byte[] data, int length) {
		data = loadByte(length);
		return data;
	}

	/**
	 * 从buff中读取指定长度的数据并转换为BigInteger
	 * 
	 * @param length
	 * @return
	 */
	public BigInteger loadBigInteger(int length) {
		return MessageUtil.toBigInteger(loadByte(length));
	}

	public static byte[] toByteArray(long data, int length) {
		byte[] bufParam = new byte[length];
		bufParam[length - 1] = (byte) data;
		for (int i = 1; i < bufParam.length; i++) {
			bufParam[length - 1 - i] = (byte) (data >>> (8 * i));
		}
		return bufParam;
	}

	/**
	 * 对传入的字节数组按字节逆序处理，该方法主要用于生成PCAP文件格式时的Packet Header的4个字段，都需要做逆序处理
	 * @param bytes
	 * @return
	 */
	public static byte[] change(byte[] bytes) {
		byte temp = 0;
		for (int i = 0; i < 2; i++) {
			temp = bytes[i];
			bytes[i] = bytes[3 - i];
			bytes[3 - i] = temp;
		}
		return bytes;
	}
}